﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace The_HTTP_Web_Server
{
    class TheHTTPWebServer
    {
        private static Boolean NotCommandline;
        static void Main(string[] args)
        {
            foreach (string arg in args)
            {
                switch (arg.ToLower())
                {
                    case "-i":
                    case "-install":
                    case "/install":
                    case "/i":
                        # region Install
                        Console.WriteLine("+----------------------------------+");
                        Console.WriteLine("|The HTTP Web Server 1.0 by Jlgager|");
                        Console.WriteLine("+----------------------------------+");
                        Console.WriteLine(" Installing to \"C:\\The HTTP Web Server\"...");
                        sInstallDirectory = sDefaultDirectory;
                        RunTasks();
                        return;
                        # endregion
                    case "-u":
                    case "-uninstall":
                    case "/uninstall":
                    case "/u":
                        #region Uninstall
                        Console.WriteLine("+----------------------------------+");
                        Console.WriteLine("|The HTTP Web Server 1.0 by Jlgager|");
                        Console.WriteLine("+----------------------------------+");
                        while (true) // Loop indefinitely
                        {
                            Console.WriteLine(" This will delete ALL files!");
                            Console.WriteLine(" Are you sure you want to uninstall? (y,n)"); // Prompt
                            Console.WriteLine(" :");
                            string response = Console.ReadLine(); // Get string from user

                            if (response == "y" || response == "Y") // Check string
                            {
                                Console.WriteLine(" Uninstalling from both locations...");
                                Uninstall = true;
                                RunTasks();
                                break;
                            }
                            else
                            {
                                Console.WriteLine(" Invalid Entry! Please Try Again!");
                            }
                        }
                        return;
                        #endregion
                    case "-start":
                    case "/start":
                        #region Start
                        TheHTTPWebServer MWS = new TheHTTPWebServer();
                        ServerRunning = true;
                        return;
                        #endregion
                    case "-stop":
                    case "/stop":
                        #region Stop
                        foreach (Process p in Process.GetProcessesByName("The HTTP Web Server"))
                        {
                            try
                            {
                                p.Kill();
                                p.WaitForExit(); // possibly with a timeout
                            }
                            catch (Win32Exception winException)
                            {
                                errorlog(winException.ToString(), winException.Message);
                            }
                            catch (InvalidOperationException invalidException)
                            {
                                errorlog(invalidException.ToString(), invalidException.Message);
                            }
                            catch (Exception e)
                            {
                                errorlog(e.ToString(), e.Message);
                            }
                        }

                        break;
                        #endregion
                    default:
                        break;
                }
            }
            NotCommandline = true;
            Load();
        }

        private static void Load()
        {
            Console.Clear();
            Console.WriteLine("+----------------------------------+");
            Console.WriteLine("|The HTTP Web Server 1.0 by Jlgager|");
            Console.WriteLine("+----------------------------------+");

            //Lists Resource Names
            //string[] array = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
            //for (int i = 0; i < array.Length; ++i) { Console.WriteLine(array[i]); }

            Uninstall = false;
            while (true) // Loop indefinitely
            {
                Console.WriteLine(" What Do You Want To Do? - Press Ctrl + C to exit."); // Prompt
                Console.WriteLine(" 1. Install to: \"C:\\The HTTP Web Server\"");
                Console.WriteLine(" 2. Install to: This Directory");
                Console.WriteLine(" 3. Uninstall");
                Console.WriteLine(" 4. Start Server");
                Console.WriteLine(" :");
                string line = Console.ReadLine(); // Get string from user

                if (line == "1") // Check string
                {
                    Console.WriteLine(" Installing to \"C:\\The HTTP Web Server\"...");
                    sInstallDirectory = sDefaultDirectory;
                    RunTasks();
                    break;
                }
                else if (line == "2")
                {
                    Console.WriteLine(" Installing to \"" + sAppDirectory + "\"...");
                    sInstallDirectory = sAppDirectory;
                    RunTasks();
                    break;
                }
                else if (line == "3")
                {
                    while (true) // Loop indefinitely
                    {
                        Console.WriteLine(" This will delete ALL files!");
                        Console.WriteLine(" Are you sure you want to uninstall? (y,n)"); // Prompt
                        Console.WriteLine(" :");
                        string response = Console.ReadLine(); // Get string from user

                        if (response == "y" || response == "Y") // Check string
                        {
                            Console.WriteLine(" Uninstalling from both locations...");
                            Uninstall = true;
                            RunTasks();
                            break;
                        }
                        else
                        { 
                            Console.WriteLine(" Invalid Entry! Please Try Again!");
                        }
                    }
                    break;
                }
                else if (line == "4")
                {
                    TheHTTPWebServer MWS = new TheHTTPWebServer();
                    ServerRunning = true;
                    break;
                }
                else { Console.WriteLine(" Invalid Entry! Please Try Again!"); }
            }
        }

        private static void RunTasks()
        {
            if (!ServerRunning)
            {
                try
                {
                    if (Uninstall)
                    {
                        sInstallDirectory = sAppDirectory;
                        DirectoryEdit();
                        sInstallDirectory = sDefaultDirectory;
                        DirectoryEdit();
                        if (Uninstall)
                        {
                            if (Directory.Exists(sDefaultDirectory))
                            {
                                Empty(sDefaultDirectory);
                                Directory.Delete(sDefaultDirectory);
                                DirectoryMessage(sDefaultDirectory, 'U', true);
                            }
                            else
                            {
                                DirectoryMessage(sDefaultDirectory, 'U', false);
                            }
                        }
                        Console.WriteLine(" The HTTP Web Server was uninstalled correctly!");
                    }
                    else
                    {
                        DirectoryEdit();
                        FileEdit();
                        Console.WriteLine(" The HTTP Web Server was installed correctly!");
                    }
                    if (NotCommandline == true)
                    {
                        Console.WriteLine(" Press any key to continue...");
                        Console.ReadLine();
                        Load();
                    }
                    else { System.Threading.Thread.Sleep(1000); }
                }
                catch (Exception e)
                {
                    if (Uninstall) { Console.WriteLine(" The HTTP Web Server uninstallation failed!"); }
                    else { Console.WriteLine(" The HTTP Web Server installation failed!"); }
                    errorlog(e.ToString(), e.Message);
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                }
            }
        }

        #region Install/Uninstall Functions

        static String sDefaultDirectory = "C:\\The HTTP Web Server\\";
        static String sInstallDirectory;
        static Boolean Uninstall = false;
        static Boolean ServerRunning = false;

        private static void ExtractFromAssembly(string ResourceName, string FileToExtractTo)
        {
            Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("The_HTTP_Web_Server.Resources." + ResourceName);
            FileStream fileStream = new FileStream(FileToExtractTo, FileMode.CreateNew);
            for (int i = 0; i < stream.Length; i++)
                fileStream.WriteByte((byte)stream.ReadByte());
            fileStream.Close();
        }

        private static void DirectoryMessage(string path, char type, bool success)
        {
            if (type == 'I')
            {
                if (!success) { Console.WriteLine(" \"" + path + "\" - Directory Already Installed"); }
                else { Console.WriteLine(" \"" + path + "\" - Directory Created Successfully"); }
            }
            else if (type == 'U')
            {
                if (!success) { Console.WriteLine(" \"" + path + "\" - Directory Does Not Exist"); }
                else { Console.WriteLine(" \"" + path + "\" - Directory Deleted Successfully"); }
            }
            System.Threading.Thread.Sleep(1000);
        }

        private static void FileMessage(string path, char type, bool success)
        {
            if (type == 'I')
            {
                if (!success) { Console.WriteLine(" \"" + path + "\" - File Already Installed"); }
                else { Console.WriteLine(" \"" + path + "\" - File Created Successfully"); }
            }
            else if (type == 'U')
            {
                if (!success) { Console.WriteLine(" \"" + path + "\" - File Does Not Exist"); }
                else { Console.WriteLine(" \"" + path + "\" - File Deleted Successfully"); }
            }
            System.Threading.Thread.Sleep(1000);
        }

        private static void FileEdit()
        {
            # region httpd.conf File Creation
            if (File.Exists(sInstallDirectory + "conf\\httpd.conf"))
            {
                FileMessage(sInstallDirectory + "conf\\httpd.conf", 'I', false);
            }
            else if (File.Exists("httpd.conf"))
            {
                File.Move(sAppDirectory + "httpd.conf", sInstallDirectory + "conf\\httpd.conf");
                FileMessage(sInstallDirectory + "conf\\httpd.conf", 'I', true);
            }
            else
            {
                ExtractFromAssembly("httpd.conf", sAppDirectory + "httpd.conf");
                File.Move(sAppDirectory + "httpd.conf", sInstallDirectory + "conf\\httpd.conf");
                FileMessage(sInstallDirectory + "conf\\httpd.conf", 'I', true);
            }
            # endregion

            # region mime.types File Creation
            if (File.Exists(sInstallDirectory + "conf\\mime.types"))
            {
                FileMessage(sInstallDirectory + "conf\\mime.types", 'I', false);
            }
            else if (File.Exists("mime.types"))
            {
                File.Move(sAppDirectory + "mime.types", sInstallDirectory + "conf\\mime.types");
                FileMessage(sInstallDirectory + "conf\\mime.types", 'I', true);
            }
            else
            {
                ExtractFromAssembly("mime.types", sAppDirectory + "mime.types");
                File.Move(sAppDirectory + "mime.types", sInstallDirectory + "conf\\mime.types");
                FileMessage(sInstallDirectory + "conf\\mime.types", 'I', true);
            }
            # endregion

            # region index.html File Creation
            if (File.Exists(sInstallDirectory + "htdocs\\index.html"))
            {
                FileMessage(sInstallDirectory + "htdocs\\index.html", 'I', false);
            }
            else if (File.Exists("index.html"))
            {
                File.Move(sAppDirectory + "index.html", sInstallDirectory + "htdocs\\index.html");
                FileMessage(sInstallDirectory + "htdocs\\index.html", 'I', true);
            }
            else
            {
                ExtractFromAssembly("index.html", sAppDirectory + "index.html");
                File.Move(sAppDirectory + "index.html", sInstallDirectory + "htdocs\\index.html");
                FileMessage(sInstallDirectory + "htdocs\\index.html", 'I', true);
            }
            # endregion
        }

        private static void DirectoryEdit()
        {
            # region conf Directory Creation
            if (Directory.Exists(sInstallDirectory + "conf"))
            {
                if (Uninstall)
                {
                    Empty(sInstallDirectory + "conf");
                    Directory.Delete(sInstallDirectory + "conf");
                    DirectoryMessage(sInstallDirectory + "conf", 'U', true);
                }
                else
                {
                    DirectoryMessage(sInstallDirectory + "conf", 'I', false);
                }
            }
            else
            {
                if (Uninstall)
                {
                    DirectoryMessage(sInstallDirectory + "conf", 'U', false);
                }
                else
                {
                    Directory.CreateDirectory(sInstallDirectory + "conf");
                    DirectoryMessage(sInstallDirectory + "conf", 'I', true);
                }
            }
            # endregion

            # region htdocs Directory Creation
            if (Directory.Exists(sInstallDirectory + "htdocs"))
            {
                if (Uninstall)
                {
                    Empty(sInstallDirectory + "htdocs");
                    Directory.Delete(sInstallDirectory + "htdocs");
                    DirectoryMessage(sInstallDirectory + "htdocs", 'U', true);
                }
                else
                {
                    DirectoryMessage(sInstallDirectory + "htdocs", 'I', false);
                }
            }
            else
            {
                if (Uninstall)
                {
                    DirectoryMessage(sInstallDirectory + "htdocs", 'U', false);
                }
                else
                {
                    Directory.CreateDirectory(sInstallDirectory + "htdocs");
                    DirectoryMessage(sInstallDirectory + "htdocs", 'I', true);
                }
            }
            # endregion
        }

        public static void Empty(string path)
        {
            System.IO.DirectoryInfo directorytoempty = new System.IO.DirectoryInfo(path);
            foreach (System.IO.FileInfo file in directorytoempty.GetFiles()) file.Delete();
            foreach (System.IO.DirectoryInfo subDirectory in directorytoempty.GetDirectories()) subDirectory.Delete(true);
        }

        # endregion

        # region Server Functions

        private TcpListener myListener;
        static String sAppDirectory = AppDomain.CurrentDomain.BaseDirectory;
        static String sServerRoot;
        static String sDocRoot;
        static int port;
        static String sShortFilePath;

        //The constructor which make the TcpListener start listening on the given port.
        //It also calls a Thread on the method StartListen(). 
        public TheHTTPWebServer()
        {
            try
            {
                Console.Clear();
                Console.WriteLine("+----------------------------------+");
                Console.WriteLine("|The HTTP Web Server 1.0 by Jlgager|");
                Console.WriteLine("+----------------------------------+");
                Console.WriteLine(" Starting Up...Please Wait...");
                
                System.Threading.Thread.Sleep(1000);
                
                sServerRoot = GetServerRootPath(sAppDirectory);
                sDocRoot = GetDocRootPath(sAppDirectory);
                port = GetListeningPort(sAppDirectory);
                sShortFilePath = "..\\" + sDocRoot.Substring(sDocRoot.LastIndexOf("\\") + 1) + "\\";

                //start listing on the given port
                myListener = new TcpListener(IPAddress.Any, port);
                myListener.Start();
                Console.Clear();
                Console.WriteLine("+----------------------------------+");
                Console.WriteLine("|The HTTP Web Server 1.0 by Jlgager|");
                Console.WriteLine("+----------------------------------+");
                Console.WriteLine(" Listening on port : " + port);
                Console.WriteLine(" Server Root : " + sServerRoot);
                Console.WriteLine(" Doc Root : " + sDocRoot);
                Console.WriteLine(" Web Server Running... Press Ctrl + C to Stop...");

                //start the thread which calls the method 'StartListen'
                Thread th = new Thread(new ThreadStart(StartListen));
                th.Start();

            }
            catch (System.Net.Sockets.SocketException e)
            {
                if (e.Message == "Only one usage of each socket address (protocol/network address/port) is normally permitted")
                {
                    Console.Clear();
                    Console.WriteLine("+----------------------------------+");
                    Console.WriteLine("|The HTTP Web Server 1.0 by Jlgager|");
                    Console.WriteLine("+----------------------------------+");
                    errorlog("Port " + port + " is already in use!\n Please edit httpd.conf to change port number!", "Port " + port + " is already in use!\n Please edit httpd.conf to change port number!");
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                    Load();
                }
            }
            catch (Exception e)
            {
                errorlog(e.ToString(), e.Message);
                if (NotCommandline == true)
                {
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                    Load();
                }
            }
        }



        //This method Accepts the new connection.
        //First it receives the welcome message from the client,
        //Then it sends the Current date time to the Client.
        public void StartListen()
        {
            try
            {
                int iStartPos = 0;
                String sRequest = "";
                String sDirName = "";
                String sRequestedFile = "";
                String sErrorMessage = "";
                String sFolderName = "";
                String sLocalDir = "";
                String sPhysicalFilePath = "";
                String sFormattedMessage = "";
                String sResponse = "";
                String sPath = "";

                if (sServerRoot == "")
                {
                    return;
                }

                while (true)
                {
                    //Accept a new connection
                    Socket mySocket = myListener.AcceptSocket();
                    Console.WriteLine("");
                    Console.WriteLine(" Socket Type " + mySocket.SocketType);
                    if (mySocket.Connected)
                    {
                        Console.WriteLine("\n Client Connected!!\n==================\nCLient IP {0}\n",
                            mySocket.RemoteEndPoint);

                        //make a byte array and receive data from the client 
                        Byte[] bReceive = new Byte[1024];
                        int i = mySocket.Receive(bReceive, bReceive.Length, 0);

                        //Convert Byte to String
                        string sBuffer = Encoding.ASCII.GetString(bReceive);

                        //At present we will only deal with GET type
                        if (sBuffer.Substring(0, 3) != "GET")
                        {
                            Console.WriteLine(" Only Get Method is supported..");
                            Console.WriteLine(" Web Server Running... Press Ctrl + C to Stop...");
                            mySocket.Close();
                            continue;
                        }

                        // Look for HTTP request
                        iStartPos = sBuffer.IndexOf("HTTP", 1);

                        // Get the HTTP text and version e.g. it will return "HTTP/1.1"
                        string sHttpVersion = sBuffer.Substring(iStartPos, 8);

                        // Extract the Requested Type and Requested file/directory
                        sRequest = sBuffer.Substring(0, iStartPos - 1);

                        //Replace backslash with Forward Slash, if Any
                        sRequest.Replace("\\", "/");

                        //If file name is not supplied add forward slash to indicate 
                        //that it is a directory and then we will look for the 
                        //default file name..
                        if ((sRequest.IndexOf(".") < 1) && (!sRequest.EndsWith("/")))
                        {
                            sRequest = sRequest + "/";
                        }

                        //Extract the requested file name
                        iStartPos = sRequest.LastIndexOf("/") + 1;
                        sRequestedFile = sRequest.Substring(iStartPos);

                        //Extract The directory Name
                        sDirName = sRequest.Substring(sRequest.IndexOf("/"), sRequest.LastIndexOf("/") - 3);

                        /////////////////////////////////////////////////////////////////////
                        // Identify the Physical Directory
                        /////////////////////////////////////////////////////////////////////
                        if (sDirName == "/")
                        {
                            sLocalDir = sDocRoot;
                            sPath = "/";
                        }
                        else
                        {
                            //Remove extra spaces
                            sDirName.Trim();

                            //Remove the slash
                            sFolderName = sDirName.Substring(1, sDirName.Length - 2);
                            sLocalDir = sDocRoot + "\\" + sFolderName;
                            sPath = sDirName;
                        }

                        Console.WriteLine(" Virtual Directory : " + sDirName);
                        Console.WriteLine(" Local Directory : " + sShortFilePath + sFolderName);

                        //If the physical directory does not exist then dispaly the error message
                        if (!Directory.Exists(sLocalDir))
                        {
                            sErrorMessage = "<H2>Error!! Requested Directory does not exist!</H2><Br>";
                            Console.WriteLine(" Error!! Requested Directory does not exist!");

                            //Format The Message
                            SendHeader(sHttpVersion, "", sErrorMessage.Length, " 404 Not Found", ref mySocket);

                            //Send to the browser
                            SendToBrowser(sErrorMessage, ref mySocket);

                            mySocket.Close();
                            Console.WriteLine(" Web Server Running... Press Ctrl + C to Stop...");

                            continue;
                        }

                        /////////////////////////////////////////////////////////////////////
                        // Identify the File Name
                        /////////////////////////////////////////////////////////////////////

                        //If The file name is not supplied then look in the default file list
                        if (sRequestedFile.Length == 0)
                        {
                            // Get the default filename
                            sRequestedFile = GetTheDefaultFileName(sAppDirectory, sLocalDir);

                            if (sRequestedFile == "")
                            {
                                sErrorMessage = "<H2>404 Error! No Default File Name Specified!</H2>";
                                Console.WriteLine("404 Error! No Default File Name Specified!");
                                SendHeader(sHttpVersion, "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
                                SendToBrowser(sErrorMessage, ref mySocket);

                                mySocket.Close();
                                Console.WriteLine(" Web Server Running... Press Ctrl + C to Stop...");

                                continue;

                            }
                        }

                        /////////////////////////////////////////////////////////////////////
                        // Get TheMime Type
                        /////////////////////////////////////////////////////////////////////

                        String sMimeType = GetMimeType(sAppDirectory, sRequestedFile);
                        //Build the physical path
                        sPhysicalFilePath = sLocalDir + "\\" + sRequestedFile;
                        if (sFolderName == "")
                        {
                            Console.WriteLine(" File Requested  : " + sShortFilePath + sRequestedFile);
                        }
                        else
                        {
                            Console.WriteLine(" File Requested  : " + sShortFilePath + sFolderName.Replace("/", "\\") + "\\" + sRequestedFile);
                        }
                        if (File.Exists(sPhysicalFilePath) == false)
                        {

                            sErrorMessage = "<H2>404 Error! File Does Not Exist!</H2>";
                            Console.WriteLine(" 404 Error! File Does Not Exist!");
                            SendHeader(sHttpVersion, "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
                            SendToBrowser(sErrorMessage, ref mySocket);

                            if (sFormattedMessage != "")
                            {
                                Console.WriteLine(" Message: " + sFormattedMessage);
                            }
                        }
                        else
                        {
                            int iTotBytes = 0;

                            sResponse = "";

                            FileStream fs = new FileStream(sPhysicalFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                            // Create a reader that can read bytes from the FileStream.
                            BinaryReader reader = new BinaryReader(fs);
                            byte[] bytes = new byte[fs.Length];
                            int read;
                            while ((read = reader.Read(bytes, 0, bytes.Length)) != 0)
                            {
                                // Read from the file and write the data to the network
                                sResponse = sResponse + Encoding.ASCII.GetString(bytes, 0, read);

                                iTotBytes = iTotBytes + read;
                            }
                            reader.Close();

                            SendHeader(sHttpVersion, sMimeType, iTotBytes, " 200 OK", ref mySocket);

                            SendToBrowser(bytes, ref mySocket);

                            //mySocket.Send(bytes, bytes.Length,0);
                        }
                        mySocket.Close();
                        Console.WriteLine(" Web Server Running... Press Ctrl + C to Stop...");
                    }
                }
            }
            catch (Exception e)
            {
                errorlog(e.ToString(), e.Message);
                Console.WriteLine(" Press any key to continue...");
                Console.ReadLine();
                Load();
            }
        }

        #region GETS

        public string GetTheDefaultFileName(string sAppDirectory, string sLocalDirectory)
        {
            StreamReader sr;
            String sLine = "";
            String sStartWord = "";
            String sString = "";
            String[] sfilenames;
            int iStartPos = 0;

            try
            {
                if (!File.Exists(sServerRoot + "httpd.conf"))
                {
                    throw new System.IO.FileNotFoundException("httpd.conf is Missing! Server Is Not Installed Correctly!");
                }
                else
                {
                    sr = new StreamReader(sServerRoot + "httpd.conf");

                    while ((sLine = sr.ReadLine()) != null)
                    {
                        //Remove extra Spaces
                        sLine.Trim();

                        if (sLine.Length > 14)
                        {
                            //find the separator
                            iStartPos = sLine.IndexOf(" ") + 1;

                            // Convert to lowercase
                            sLine = sLine.ToLower();

                            sStartWord = sLine.Substring(0, 14);
                            sString = sLine.Substring(iStartPos);
                            if (sStartWord == "directoryindex")
                            {
                                sfilenames = sString.Split(' ');
                                foreach (string filename in sfilenames)
                                {
                                    if (File.Exists(sLocalDirectory + "\\" + filename))
                                    {
                                        return filename;
                                    }
                                }
                            }
                        }
                    }
                    return "";
                }
            }
            catch (Exception e)
            {
                errorlog(e.ToString(), e.Message);
                if (NotCommandline == true)
                {
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                    Load();
                }
            }
            return "";
        }

        public static string GetServerRootPath(string sAppDirectory)
        {

            StreamReader sr;
            String sLine = "";
            String sStartWord = "";
            String sServerRoot = "";
            int iStartPos = 0;
            try
            {
                if (!File.Exists(sAppDirectory + "conf\\httpd.conf") && !File.Exists(sAppDirectory + "httpd.conf") && !File.Exists(sDefaultDirectory + "conf\\httpd.conf"))
                {
                    throw new System.IO.FileNotFoundException("httpd.conf is Missing! Server Is Not Installed Correctly!");
                }
                else
                {
                    if (File.Exists(sDefaultDirectory + "conf\\httpd.conf"))
                    {
                        sr = new StreamReader(sDefaultDirectory + "conf\\httpd.conf");
                    }
                    else if (File.Exists(sAppDirectory + "conf\\httpd.conf"))
                    {
                        sr = new StreamReader(sAppDirectory + "conf\\httpd.conf");
                    }
                    else if (File.Exists(sAppDirectory + "httpd.conf"))
                    {
                        sr = new StreamReader(sAppDirectory + "httpd.conf");
                    }
                    else
                    {
                        sr = new StreamReader(sAppDirectory + "ERROR");
                    }

                    while ((sLine = sr.ReadLine()) != null)
                    {
                        //Remove extra Spaces
                        sLine.Trim();

                        if (sLine.Length > 10)
                        {
                            //find the separator
                            iStartPos = sLine.IndexOf(" ") + 2;

                            // Convert to lowercase
                            sLine = sLine.ToLower();

                            sStartWord = sLine.Substring(0, 10);
                            sServerRoot = sLine.Substring(iStartPos);
                            if (sServerRoot.EndsWith("\"")) { sServerRoot = sServerRoot.Substring(0, sServerRoot.Length - 1); }
                            if (!sServerRoot.EndsWith("\\")) { sServerRoot += "\\"; }
                            if (sStartWord == "serverroot") { return sServerRoot; }
                        }
                    }
                    return "";
                }
            }
            catch (Exception e)
            {
                errorlog(e.ToString(), e.Message);
                if (NotCommandline == true)
                {
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                    Load();
                }
            }
            return "";
        }

        public static string GetDocRootPath(string sAppDirectory)
        {
            StreamReader sr;
            String sLine = "";
            String sStartWord = "";
            int iStartPos = 0;

            try
            {
                if (!File.Exists(sServerRoot + "httpd.conf"))
                {
                    throw new System.IO.FileNotFoundException("httpd.conf is Missing! Server Is Not Installed Correctly!");
                }
                else
                {
                    if (File.Exists(sDefaultDirectory + "conf\\httpd.conf"))
                    {
                        sr = new StreamReader(sDefaultDirectory + "conf\\httpd.conf");
                    }
                    else if (File.Exists(sAppDirectory + "conf\\httpd.conf"))
                    {
                        sr = new StreamReader(sAppDirectory + "conf\\httpd.conf");
                    }
                    else if (File.Exists(sAppDirectory + "httpd.conf"))
                    {
                        sr = new StreamReader(sAppDirectory + "httpd.conf");
                    }
                    else
                    {
                        sr = new StreamReader(sAppDirectory + "ERROR");
                    }

                    while ((sLine = sr.ReadLine()) != null)
                    {
                        //Remove extra Spaces
                        sLine.Trim();

                        if (sLine.Length > 12)
                        {
                            //find the separator
                            iStartPos = sLine.IndexOf(" ") + 2;

                            // Convert to lowercase
                            sLine = sLine.ToLower();

                            sStartWord = sLine.Substring(0, 12);
                            sDocRoot = sLine.Substring(iStartPos);
                            if (sDocRoot.EndsWith("\""))
                            {
                                sDocRoot = sDocRoot.Substring(0, sDocRoot.Length - 1);
                            }
                            if (sStartWord == "documentroot")
                            {
                                return sDocRoot;
                            }
                        }
                    }
                    return "";
                }
            }
            catch (Exception e)
            {
                errorlog(e.ToString(), e.Message);
                if (NotCommandline == true)
                {
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                    Load();
                }
            }
            return "";
        }

        public static int GetListeningPort(string sAppDirectory)
        {
            StreamReader sr;
            String sLine = "";
            String sStartWord = "";
            String sListeningPort = "";
            int iStartPos = 0;

            try
            {
                if (!File.Exists(sServerRoot + "httpd.conf"))
                {
                    throw new System.IO.FileNotFoundException("httpd.conf is Missing! Server Is Not Installed Correctly!");
                }
                else
                {
                    sr = new StreamReader(sServerRoot + "httpd.conf");

                    while ((sLine = sr.ReadLine()) != null)
                    {
                        //Remove extra Spaces
                        sLine.Trim();

                        if (sLine.Length > 6)
                        {
                            //find the separator
                            iStartPos = sLine.IndexOf(" ") + 1;

                            // Convert to lowercase
                            sLine = sLine.ToLower();

                            sStartWord = sLine.Substring(0, 6);
                            sListeningPort = sLine.Substring(iStartPos);
                            if (sStartWord == "listen")
                            {
                                return Convert.ToInt16(sListeningPort);
                            }
                        }
                    }
                    return 80;
                }
            }
            catch (Exception e)
            {
                errorlog(e.ToString(), e.Message);
                if (NotCommandline == true)
                {
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                    Load();
                }
            }
            return 80;
        }

        public string GetMimeType(string sAppDirectory, string sRequestedFile)
        {


            StreamReader sr;
            String sLine = "";
            String sMimeType = "";
            String sFileExt = "";
            String sMimeExt = "";

            // Convert to lowercase
            sRequestedFile = sRequestedFile.ToLower();

            int iStartPos = sRequestedFile.IndexOf(".");

            sFileExt = sRequestedFile.Substring(iStartPos);

            try
            {
                //Open the mime.types to identify the MIME type, using the file extension supplied by the user
                if (!File.Exists(sServerRoot + "mime.types"))
                {
                    throw new System.IO.FileNotFoundException("mime.types is Missing! Server Is Not Installed Correctly!");
                }
                else
                {
                    sr = new StreamReader(sServerRoot + "mime.types");

                    while ((sLine = sr.ReadLine()) != null)
                    {

                        sLine.Trim();

                        if (sLine.Length > 0)
                        {
                            //find the separator
                            iStartPos = sLine.IndexOf(";");

                            // Convert to lower case
                            sLine = sLine.ToLower();

                            sMimeExt = sLine.Substring(0, iStartPos);
                            sMimeType = sLine.Substring(iStartPos + 1);

                            if (sMimeExt == sFileExt)
                                break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                errorlog(e.ToString(), e.Message);
                if (NotCommandline == true)
                {
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                    Load();
                }
            }

            if (sMimeExt == sFileExt)
                return sMimeType;
            else
                return "";
        }

        #endregion

        #region SENDS

        /// <summary>
        /// This function send the Header Information to the client (Browser)
        /// </summary>
        /// <param name="sHttpVersion">HTTP Version</param>
        /// <param name="sMIMEHeader">Mime Type</param>
        /// <param name="iTotBytes">Total Bytes to be sent in the body</param>
        /// <param name="mySocket">Socket reference</param>
        /// <returns></returns>
        public void SendHeader(string sHttpVersion, string sMIMEHeader, int iTotBytes, string sStatusCode, ref Socket mySocket)
        {

            String sBuffer = "";

            // if Mime type is not provided set default to text/html
            if (sMIMEHeader.Length == 0)
            {
                sMIMEHeader = "text/html";  // Default Mime Type is text/html
            }

            sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n";
            sBuffer = sBuffer + "Server: cx1193719-b\r\n";
            sBuffer = sBuffer + "Content-Type: " + sMIMEHeader + "\r\n";
            sBuffer = sBuffer + "Accept-Ranges: bytes\r\n";
            sBuffer = sBuffer + "Content-Length: " + iTotBytes + "\r\n\r\n";

            Byte[] bSendData = Encoding.ASCII.GetBytes(sBuffer);

            SendToBrowser(bSendData, ref mySocket);

            Console.WriteLine(" Total Bytes : " + iTotBytes.ToString());

        }

        /// <summary>
        /// Overloaded Function, takes string, convert to bytes and calls 
        /// overloaded sendToBrowserFunction.
        /// </summary>
        /// <param name="sData">The data to be sent to the browser(client)</param>
        /// <param name="mySocket">Socket reference</param>
        public void SendToBrowser(String sData, ref Socket mySocket)
        {
            SendToBrowser(Encoding.ASCII.GetBytes(sData), ref mySocket);
        }

        /// <summary>
        /// Sends data to the browser (client)
        /// </summary>
        /// <param name="bSendData">Byte Array</param>
        /// <param name="mySocket">Socket reference</param>
        public void SendToBrowser(Byte[] bSendData, ref Socket mySocket)
        {
            int numBytes = 0;

            try
            {
                if (mySocket.Connected)
                {
                    if ((numBytes = mySocket.Send(bSendData, bSendData.Length, 0)) == -1)
                        Console.WriteLine(" Socket Error cannot Send Packet");
                    else
                    {
                        Console.WriteLine(" No. of bytes send {0}", numBytes);
                    }
                }
                else
                    Console.WriteLine(" Connection Dropped....");
            }
            catch (Exception e)
            {
                Console.WriteLine(" Error Occurred : {0} ", e);
                errorlog(e.ToString(), e.Message);
            }
        }

        #endregion

        # endregion

        private static void command_line_error(string errormessage)
        {
            Console.Clear();
            Console.WriteLine("+----------------------------------+");
            Console.WriteLine("|The HTTP Web Server 1.0 by Jlgager|");
            Console.WriteLine("+----------------------------------+");
            Console.WriteLine(" An Exception Occurred : " + errormessage);
        }

        private static void errorlog(string errorstring, string errormessage)
        {
            try
            {
                string filename;
                TextWriter tw;
                
                if (sServerRoot != null) { filename = sServerRoot + "\\ERRORLOG.log"; }
                else
                {
                    Directory.CreateDirectory(sAppDirectory + "\\conf");
                    filename = sAppDirectory + "\\conf\\ERRORLOG.log";
                }

                // create a writer and open the file
                if (File.Exists(filename)) { tw = File.AppendText(filename); tw.WriteLine(""); }
                else { tw = new StreamWriter(filename); }

                // write date and error text to the file
                tw.WriteLine(DateTime.Now);
                tw.WriteLine("An Exception Occurred :" + errorstring);

                // close the stream
                tw.Close();

                if (NotCommandline == true)
                {
                    Console.WriteLine(" An Exception Occurred : " + errormessage);

                    while (true) // Loop indefinitely
                    {
                        Console.WriteLine(" Do you want to open the ERRORLOG file? (y,n)");
                        string line = Console.ReadLine(); // Get string from user
                        if (line == "y" || line == "Y") // Check string
                        {
                            if (sServerRoot == null || sServerRoot == "")
                            {
                                Process.Start("notepad.exe", sAppDirectory + "conf\\ERRORLOG.log");
                            }
                            else
                            {
                                Process.Start("notepad.exe", sServerRoot + "conf\\ERRORLOG.log");
                            }
                            break;
                        }
                        else if (line == "n" || line == "N") { break; }
                        else { Console.WriteLine(" Invalid Entry! Please Try Again!"); }
                    }
                    while (true) // Loop indefinitely
                    {
                        Console.WriteLine(" Do you want to clear the ERRORLOG file? (y,n)");
                        string line = Console.ReadLine(); // Get string from user
                        if (line == "y" || line == "Y") // Check string
                        {
                            if (sServerRoot == null || sServerRoot == "")
                            {
                                if (File.Exists(sAppDirectory + "conf\\ERRORLOG.log"))
                                { File.Delete(sAppDirectory + "conf\\ERRORLOG.log"); }
                            }
                            else
                            {
                                if (File.Exists(sServerRoot + "conf\\ERRORLOG.log"))
                                { File.Delete(sServerRoot + "conf\\ERRORLOG.log"); }
                            }
                            break;
                        }
                        else if (line == "n" || line == "N") { break; }
                        else { Console.WriteLine(" Invalid Entry! Please Try Again!"); }
                    }
                }
                else
                {
                    command_line_error(errormessage);
                    System.Threading.Thread.Sleep(1000);

                    command_line_error(errormessage);
                    Console.WriteLine(" 5..");
                    System.Threading.Thread.Sleep(1000);

                    command_line_error(errormessage);
                    Console.WriteLine(" 4..");
                    System.Threading.Thread.Sleep(1000);

                    command_line_error(errormessage);
                    Console.WriteLine(" 3..");
                    System.Threading.Thread.Sleep(1000);

                    command_line_error(errormessage);
                    Console.WriteLine(" 2..");
                    System.Threading.Thread.Sleep(1000);

                    command_line_error(errormessage);
                    Console.WriteLine(" 1..");
                    System.Threading.Thread.Sleep(1000);

                    command_line_error(errormessage);
                    Console.WriteLine(" 0..");
                    System.Threading.Thread.Sleep(1000);

                    command_line_error(errormessage);
                    Environment.Exit(1);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                //errorlog(e.ToString(), e.Message);
                if (NotCommandline == true)
                {
                    Console.WriteLine(" Press any key to continue...");
                    Console.ReadLine();
                    Load();
                }
            }
        }
    }
}
